﻿using System;
using System.IO;
using System.Text;
using System.Web.Security;
using Dexter.Dependency.Installation;
using Dexter.Domain.Model;
using Dexter.Repository;
using Dexter.Security;
using Dexter.Storage;

namespace Dexter.Services.Implementation {
	/// <summary>
	/// 	The implementatio of <see cref = "ISetupService" />.
	/// </summary>
	public class SetupService : ISetupService , ISetupControl {
		readonly ICategoryService categoryService;
		readonly IConfigurationRepository configurationRepository;
		readonly IEncryptionService encryptionService;
		readonly IGlobalRepository globalRepository;
		readonly IPostService postService;
		readonly IStorageProvider storageProvider;

		/// <summary>
		/// 	Initializes a new instance of the <see cref = "SetupService" /> class.
		/// </summary>
		/// <param name = "globalRepository">The global repository.</param>
		/// <param name = "storageProvider">The storage provider.</param>
		/// <param name = "configurationRepository">The configuration repository.</param>
		/// <param name = "categoryService">The category service.</param>
		/// <param name = "encryptionService">The encryption service.</param>
		/// <param name = "postService">The post service.</param>
		public SetupService ( IGlobalRepository globalRepository , IStorageProvider storageProvider , IConfigurationRepository configurationRepository , ICategoryService categoryService , IEncryptionService encryptionService , IPostService postService ) {
			this.globalRepository = globalRepository;
			this.configurationRepository = configurationRepository;
			this.categoryService = categoryService;
			this.encryptionService = encryptionService;
			this.postService = postService;
			this.storageProvider = storageProvider;
		}

		#region ISetupService Members

		/// <summary>
		/// 	Gets a value indicating whether this engine is installed.
		/// </summary>
		/// <value>
		/// 	<c>true</c> if this engine is installed; otherwise, <c>false</c>.
		/// </value>
		public bool IsInstalled {
			get { return storageProvider.FileExist ( "App_Data\\Setup\\complete.dxt" ); }
		}

		/// <summary>
		/// 	Inizializeds the schema of the database;
		/// </summary>
		public void Inizialize ( SiteConfiguration configuration , bool createSchema , string connectionString , string username , string password , string email , string databaseType , string databaseSchema , string databaseTablePrefix ) {
			if ( createSchema ) {
				globalRepository.SaveConfiguration ( connectionString , databaseType , databaseSchema , true , databaseTablePrefix );
				globalRepository.InizializeRepositorySchema ( );
			}

			var conf = configurationRepository.GetConfiguration ( )
			           ?? new Configuration ( ) {SerializedConfiguration = configuration.Serialize ( )};

			configurationRepository.SaveConfiguration ( conf );
			encryptionService.CreateNewKey ( );

			if ( !Roles.RoleExists ( "Administrator" ) ) {
				Roles.CreateRole ( "Administrator" );
			}

			if ( !Roles.RoleExists ( "Poster" ) ) {
				Roles.CreateRole ( "Poster" );
			}

			var user = Membership.GetUser ( username );

			if ( user == null ) {
				Membership.CreateUser ( username , password , email );
			}

			Roles.AddUserToRole ( username , "Poster" );
			Roles.AddUserToRole ( username , "Administrator" );

			var defaultCategory = categoryService.GetDefaultCategoryWithChilds ( );

			if ( defaultCategory == null ) {
				defaultCategory = Category.CreateNewCategory ( "Various" , null );
				defaultCategory.IsDefaultCategory = true;

				categoryService.Save ( defaultCategory );
			}

			var filePath = storageProvider.Combine ( storageProvider.PrivateRoot , "Setup\\defaultPost.dxt" );
			IStorageFile defaultPost = storageProvider.GetFile ( filePath );

			string formattedBody;

			using ( var sr = defaultPost.OpenRead ( ) ) {
				var bytes = sr.GetAllBytes ( );
				formattedBody = Encoding.ASCII.GetString ( bytes ).Replace ( "[SiteDomain]" , configuration.UrlBuilder.SiteDomain );
			}

			Post pst = Post.CreateNewPublishedPost ( "Welcome to Dexter!" , defaultCategory , formattedBody , username );
			postService.Save ( pst );


			var completeFilePath = storageProvider.Combine ( storageProvider.PrivateRoot , "Setup\\complete.dxt" );
			storageProvider.CreateFile ( completeFilePath );
		}

		#endregion
	}
}